import redis

from common import constants
from config import configuration


class SingleRedisClient:
    # Redis 客户端对象
    __redis_client = None

    def __new__(cls):
        if cls.__redis_client is None:
            cls._instance = super().__new__(cls)
            print("正在连接到Redis服务器{}:{}".format(configuration.REDIS_HOST, configuration.REDIS_POST))
            # 公共参数
            connection_params = {
                'host': configuration.REDIS_HOST,
                'port': configuration.REDIS_POST,
                'db': 0,
                'socket_timeout': 5
            }
            # 配置不同的验证方式
            if len(configuration.REDIS_USERNAME) > 0:
                # 启用了 ACL 功能时，通常需要同时指定用户名和密码
                connection_params['username'] = configuration.REDIS_USERNAME
                connection_params['password'] = configuration.REDIS_PASSWORD
            elif len(configuration.REDIS_PASSWORD) > 0:
                # 默认模式仅使用密码
                connection_params['password'] = configuration.REDIS_PASSWORD
            # 创建 Redis 连接
            cls.__redis_client = redis.StrictRedis(**connection_params)
            # 测试连接
            cls.test_connection()
            print("连接成功。")
        return cls.__redis_client

    @classmethod
    def test_connection(cls):
        cls.__redis_client.set("test_key", "test_value")
        cls.__redis_client.delete("test_key")


class RedisService:

    def __init__(self):
        self.__redis_client = SingleRedisClient()

    def set_cache(self, cache_key, val, expire_time):
        self.__redis_client.set(cache_key, val, nx=True, ex=expire_time)

    def get_cache(self, cache_key):
        val = self.__redis_client.get(cache_key)
        if val is not None:
            return val.decode('utf-8')
        return val

    def del_cache(self, cache_key):
        self.__redis_client.delete(cache_key)

    def set_ding_access_token(self, app_key, app_secret, access_token, expire_time):
        cache_key = f"{constants.ACCESS_TOKEN_CACHE_KEY}:{app_key}:{app_secret}"
        # 为防止 token 过期，凭证的有效时间每分钟都需要重新获取一次
        if expire_time > 60:
            expire_time = 60
        else:
            expire_time = expire_time // 2
        self.set_cache(cache_key, access_token, expire_time)

    def get_ding_access_token(self, app_key, app_secret):
        cache_key = f"{constants.ACCESS_TOKEN_CACHE_KEY}:{app_key}:{app_secret}"
        return self.get_cache(cache_key)
